<?php

namespace app\common\library;

use alipay\aop\AopClient;
use alipay\aop\request\AlipayTradeRefundRequest;
use Alipay\EasySDK\Kernel\Config;
use Alipay\EasySDK\Kernel\Factory;
use app\api\server\Refund as ServerRefund;
use app\common\model\MoneyLog;
use app\common\model\order\Goods;
use app\common\model\order\Order;
use app\common\model\order\Refund as OrderRefund;
use app\common\model\User;
use stdClass;
use think\Db;
use think\Env;
use think\Log;
use wechatPay\Wxpay;

/**
 * 统一退款
 */
class Refund
{
    //微信退款
    public static function refund($id, $refund_order)
    {

        //商户订单号,微信生成的退款订单号 二选一即可
        $order = Order::get($refund_order['order_id']);
        $refund_money = $refund_order['refund_fee'];
        if (Env::get('app.debug') == true) {
            $refund_money = 0.01;
        }
        $time = time();
        $refundData = [
            'out_refund_no' => $refund_order['refund_sn'],
            'reason' => '商品退款',
            'notify_url' =>  cdnurl('/api/notify/refundNotify', true), //需根据自己的情况修改回调接口，也可以为空
            'funds_account' => 'AVAILABLE',
            'amount' => [
                'refund' => floatval($refund_money) * 100, //退款标价金额，单位为分，可以做部分退款
                'total' => floatval($refund_money) * 100, //订单总金额，单位为分
                'currency' => 'CNY'
            ]
        ];

        $refundData['transaction_id'] = $order['transaction_id'];
        $url = 'https://api.mch.weixin.qq.com/v3/refund/domestic/refunds';
        $urlarr = parse_url($url); //拆解为：[scheme=>https,host=>api.mch.weixin.qq.com,path=>/v3/pay/transactions/native]

        $mchid = Env::get('wechat.mchid'); //商户ID
        $xlid = Env::get('wechat.xlid'); //证书序列号

        $refundData = json_encode($refundData);
        $nonce = Pay::getNonceStr();
        $key = Pay::getSign($refundData, $urlarr['path'], $nonce, $time);
        $token = sprintf('mchid="%s",serial_no="%s",nonce_str="%s",timestamp="%d",signature="%s"', $mchid, $xlid, $nonce, $time, $key);
        $header  = array(
            'Accept: application/json',
            'Content-Type: application/json',
            'User-Agent:*/*',
            'Authorization: WECHATPAY2-SHA256-RSA2048 ' . $token
        );
        $res = Pay::curl_post_https($url, $refundData, $header);
        $res_array = json_decode($res, true);
        if (isset($res_array['status']) && ($res_array['status'] == 'PROCESSING' || $res_array['status'] == 'SUCCESS') && isset($res_array['status'])) {
            return true;
        } else {
            exception($res_array['message']);
        }
    }

    //支付宝退款
    public static function aliRefund($refund_money, $out_refund_no)
    {

        $options = new Config();
        $options->protocol = 'https';
        $options->gatewayHost = 'openapi.alipay.com';
        $options->signType = 'RSA2'; //env('ALIPAY_SIGN_TYPE');

        $options->appId = config('site.alipay_appid');



        // 为避免私钥随源码泄露，推荐从文件中读取私钥字符串而不是写入源码中
        $options->merchantPrivateKey = config('site.alipay_private_key');

        // $options->alipayCertPath = '<-- 请填写您的支付宝公钥证书文件路径，例如：/foo/alipayCertPublicKey_RSA2.crt -->';
        // $options->alipayRootCertPath = '<-- 请填写您的支付宝根证书文件路径，例如：/foo/alipayRootCert.crt" -->';
        // $options->merchantCertPath = '<-- 请填写您的应用公钥证书文件路径，例如：/foo/appCertPublicKey_2019051064521003.crt -->';

        // $options->alipayCertPath = base_path('data/cert') . '/alipayCertPublicKey_RSA2.crt';
        // $options->alipayRootCertPath = base_path('data/cert') . '/alipayRootCert.crt';
        // $options->merchantCertPath = base_path('data/cert') . '/appCertPublicKey_2021002147645197.crt';

        //注：如果采用非证书模式，则无需赋值上面的三个证书路径，改为赋值如下的支付宝公钥字符串即可
        $options->alipayPublicKey = config('site.alipay_public_key');

        //可设置异步通知接收服务地址（可选）
        $options->notifyUrl = cdnurl('/api/notify/alipayNotify', true);

        //可设置AES密钥，调用AES加解密相关接口时需要（可选）
        // $options->encryptKey = "<-- 请填写您的AES密钥，例如：aa4BtZ4tspm2wnXLb1ThQA== -->";
        Factory::setOptions($options);
        // $this->options = $options;

        try {
            //2. 发起API调用（以支付能力下的统一收单交易创建接口为例）
            $result = Factory::payment()->common()->refund($out_refund_no, $refund_money);
            if (!empty($result->code) && $result->code == 10000) {
                Refund::unify_refund($out_refund_no, $refund_money);
            } else {
                exception("调用失败，原因：" . $result->msg . "，" . $result->subMsg . PHP_EOL);
            }
        } catch (\Exception $e) {
            exception("调用失败，" . $e->getMessage() . PHP_EOL);
        }
        return true;
    }
    //积分退款
    public static function pointsRefund($refund_money, $out_refund_no)
    {
        Db::startTrans();
        try {
            $refund_order = OrderRefund::get(['refund_sn' => $out_refund_no]);
            if (!$refund_order) {
                exception("退款失败：订单不存在");
            }
            User::score($refund_order->refund_fee, $refund_order->user_id, '售后退款', $refund_order->order_id);
            Refund::unify_refund($out_refund_no, $refund_money);
            Db::commit();
        } catch (\Exception $e) {
            Db::rollback();
            Log::error("调用失败，原因：" . $e->getMessage() . "，" . PHP_EOL);
            exception($e->getMessage());
        }
    }
    public static function unify_refund($out_refund_no, $refund_money)
    {
        Db::startTrans();
        try {
            $refund_order = OrderRefund::get(['refund_sn' => $out_refund_no]);
            if (!$refund_order) {
                exception("退款失败：订单不存在");
            }
            $refund_order->refund_status = '20';
            $refund_order->teketime = time();
            $ordergoods = Goods::get($refund_order['o_g_id']);
            if (!$ordergoods) {
                exception("退款失败：订单商品不存在");
            }
            $ordergoods->refund_status = '20';
            $ordergoods->save();
            $refund_order->save();
            ServerRefund::check_after($refund_order['order_id']);
            Db::commit();
        } catch (\Exception $e) {
            Db::rollback();
            Log::error("调用失败，原因：" . $e->getMessage() . "，" . PHP_EOL);
            exception($e->getMessage());
        }
    }
}
